#ifndef YIGGLWIDGET_H
#define YIGGLWIDGET_H

// System includes
#include <QGLWidget>
#include <QThread>
#include <QReadLocker>
#include <QReadWriteLock>
#include <QTimer>

// Local includes
#include "sc++/libscsynth/scsynthprocess.h"
#include "sc++/server.h"

class YigGLThread;
class YigNetworkChannelView;

/**
*   @class YigGLWidget used for displaying opengl ontop of our YigGraphicsView
*/
class YigGLWidget : public QGLWidget
{
    Q_OBJECT

public:
    explicit YigGLWidget(QWidget *parent = 0);
    ~YigGLWidget();
    void startRendering();
    void stopRendering();

    void resize(const QSize &size);
    /** overridden for concurrent access */
    QPixmap renderPixmap(int w, int h, bool useContext);

    /**
    *   getGLThread() returns a pointer to the glThread for making signal/slot connections
    *   @return YigGLThread* the pointer to the internal QThread that actually runs the opengl rendering ontop of the QGraphicsView/Scene
    */
    YigGLThread* getGLThread();

signals:

public slots:

protected:

    void resizeEvent(QResizeEvent *event);
    void paintEvent(QPaintEvent *);
    void closeEvent(QCloseEvent *event);

private:

    YigGLThread* glThread;
    QReadWriteLock lock;
};

/**
*   @class YigGLThread lets us do our rendering in another thread, so as not to interrup the more important threads for the GUI/AUDIO
*/
class YigGLThread : public QThread
{
    Q_OBJECT

public:

    YigGLThread(YigGLWidget* _glWidget);

    /**
    *   YigGLThread deconstructor cleans up the audio buffers
    */
    ~YigGLThread();

    void resizeViewport(const QSize &size);
    /** overriddent to start buffer timer */
    void start(Priority p);
    void run();
    void stop();

    /**
    *   setServerOptions sets the server options which we use to create new AudioBuffers with
    *   @param ServerOptions the instance of server options for the current scsynth server
    */
    void setServerOptions(ServerOptions _options);

    void setView(YigNetworkChannelView* _view);

    bool pause;

signals:

    /**
    *   requestAudioBuffer is emitted when a new frame is requested and the snd buffers to be refilled
    *   @param QHash<int, SndBuf>* pointer to our internal buffer map
    */
    void requestAudioBuffers(QHash<int, AudioBuffer>* buffers);

public slots:

    /** addSynthBuffer adds a new SndBuf/Synth pos to the internal hash maps and allows for synth animation buffer map updates
    *   @param int The audioOutBus index for the synth
    */
    void addSynth(int index, QPointF pos);

    /** removeSynthBuffer removes a SndBuf/Synth pos from the internal hash maps and allows for synth animation buffer map updates
    *   @param int The audioOutBus index for the synth
    */
    void removeSynth(int index);

    /** update the position of the synth at the given audio index */
    void setSynthPos(int index, QPointF pos);

private slots:

    /** check if we have buffers and emit the data request */
    void prepareBufferRequest();

private:

    bool doRendering;
    bool doResize;
    int w, h, rotAngle;
    YigGLWidget* glWidget;
    YigNetworkChannelView* view;
    QReadWriteLock lock;
    /** map of the current audio buffers to be drawn */
    QHash<int, AudioBuffer>* currentBuffers;
    /** map of the current synth locations by audio index */
    QHash<int, QPointF> currentSynths;
    /** server options to create new audio buffers with */
    ServerOptions options;
    QTimer bufferTimer;
    int sleepTime;
};

#endif // YIGGLWIDGET_H
